﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Reflection;
using System.Configuration;
using System.Web;
using Cherry.Agile.Core;
using Cherry.Agile.Logging;
namespace Cherry.Agile.RpcService
{
    /// <summary>
    /// RpcService Config manager
    /// 优化配置加载，处理通过模块属性加载配置的方式
    /// </summary>
    public class ServiceConfigManagerV2 : System.Configuration.IConfigurationSectionHandler
    {
        private static object lockHelper = new object();
        private static ServiceConfigInfo _config;

        /// <summary>
        /// 加载跟踪
        /// </summary>
        private static StringBuilder Tracer = new StringBuilder(1024);

        /// <summary>
        /// 加载跟踪
        /// </summary>
        /// <param name="messages"></param>
        private static void _t(params string[] messages)
        {
            foreach (string s in messages)
                Tracer.Append(s);
            Tracer.AppendLine();
        }

        /// <summary>
        /// 加载跟踪
        /// </summary>
        /// <param name="message"></param>
        /// <param name="ex"></param>
        private static void _t(string message, Exception ex)
        {
            Tracer.AppendFormat("{0}:{1}", message, ex.Message, ex.StackTrace);
            Tracer.AppendLine();
        }

        //用于记录已加载的模块，避免重复加载
        private static List<string> LoadedAssemblyModule = new List<string>();

        private static void loadConfig(XmlNode section)
        {
            //ServiceConfigInfo config = new ServiceConfigInfo();
            if (_config == null)
                _config = new ServiceConfigInfo();
            try
            {

                //开启或关闭处理上下文的跟踪
                _config.TraceEnabled = section.GetBool("TraceEnabled");// section.Attributes["TraceEnabled"] == null ? true : Convert.ToBoolean(section.Attributes["TraceEnabled"].Value);

                #region 系统和业务插件程序集列表
                XmlNode assemblyListNode = section.SelectSingleNode("AssemblyList");
                if (assemblyListNode != null)
                {
                    foreach (XmlNode node in assemblyListNode.ChildNodes)
                    {
                        try
                        {
                            if (node.NodeType == XmlNodeType.Comment)
                                continue;
                            string name = node.Attributes["Name"].Value;
                            if (_config.AssemblyList.ContainsKey(name))
                                continue; //避免重复配置加载
                            string nameSpace = node.Attributes["NameSpace"].Value;
                            string value = node.Attributes["Assembly"].Value;
                            Assembly assembly = Assembly.Load(value);
                            if (assembly == null)
                                continue;
                            AssemblyInfo assemblyInfo = new AssemblyInfo()
                            {
                                Name = name,
                                NameSpace = nameSpace,
                                Assembly = assembly
                            };
                            _config.AssemblyList.Add(name, assemblyInfo);
                        }
                        catch (Exception ex)
                        {
                            _t("Read AssemblyList Node Error.", ex);
                        }
                    }
                }
                #endregion

                #region 服务处理过程，每一个版本的数据协议有一个对应的处理程序 CoreProcessor
                XmlNode coreProcessorNodeList = section.SelectSingleNode("CoreProcessor");
                if (coreProcessorNodeList != null)
                {
                    foreach (XmlNode node in coreProcessorNodeList.ChildNodes)
                    {
                        try
                        {
                            if (node.NodeType == XmlNodeType.Comment)
                                continue;
                            string version = node.Get("Version");
                            string assemblyName = node.Get("AssemblyName");
                            string className = node.Get("ClassName");

                            Version ver = new Version(version);
                            if (ver == null)
                                continue;
                            AssemblyInfo assembly = _config.AssemblyList[assemblyName];
                            IServiceProcessor serviceProcessor = assembly.Assembly.CreateInstance(string.Format("{0}.{1}", assembly.NameSpace, className)) as IServiceProcessor;
                            if (_config.ServiceProcessor == null)
                                _config.ServiceProcessor = new Dictionary<Version, IServiceProcessor>();
                            _config.ServiceProcessor.AddOrSet(ver, serviceProcessor);
                        }
                        catch (Exception ex)
                        {
                            _t("Read CoreProcessor Node Error.", ex);
                        }
                    }
                }
                #endregion


                #region 处理ProcessModuleAssemblyList，通过Attribute自动加载模块
                XmlNode processModuleAssemblyList = section.SelectSingleNode("ProcessModuleAssemblyList");
                if (processModuleAssemblyList != null)
                {
                    foreach (XmlNode node in processModuleAssemblyList.ChildNodes)
                    {
                        try
                        {
                            if (node.NodeType == XmlNodeType.Comment)
                                continue;
                            string asmName = node.Attributes["Assembly"].Value;
                            if (LoadedAssemblyModule.Contains(asmName))
                                continue;
                            Assembly assembly = Assembly.Load(asmName);
                            if (assembly == null)
                                continue;
                            IEnumerable<Type> typeList = assembly.GetTypes().Where(t =>
                            {
                                return t.IsPublic && t.IsClass
                                    && t.GetInterface("IServiceProcessor") != null
                                    && t.GetCustomAttributes(typeof(ServiceProcessorAttribute), false).Length != 0;
                                ;
                            });
                            foreach (Type t in typeList)
                            {
                                ServiceProcessorAttribute att = t.GetCustomAttributes(typeof(ServiceProcessorAttribute), false)[0] as ServiceProcessorAttribute;
                                if (att.Disabled)
                                    continue;
                                object processor = t.Assembly.CreateInstance(t.FullName);
                                int requestCode = att.BusinessCode << 16 | att.FunctionCode;
                                ProcessModuleInfo module = new ProcessModuleInfo(processor)
                                {
                                    RequestCode = requestCode,
                                    RequireValidate = att.RequireValidate,
                                    Description = att.Description,
                                    ClassName = t.Name,
                                    AssemblyName = assembly.FullName
                                };
                                _config.ProcessModuleList.Add(module.RequestCode, module);
                            }
                            LoadedAssemblyModule.Add(asmName);
                        }
                        catch (Exception ex)
                        {
                            _t("Read AssemblyList Node Error.", ex);
                        }
                    }
                }
                #endregion

                #region 业务处理插件列表ProcessModuleList
                XmlNode processModuleNodeList = section.SelectSingleNode("ProcessModuleList");
                if (processModuleNodeList != null)
                {
                    foreach (XmlNode node in processModuleNodeList.ChildNodes)
                    {
                        try
                        {
                            if (node.NodeType == XmlNodeType.Comment)
                                continue;
                            string[] rq = node.Attributes["RequestCode"].Value.Split(',');
                            int requestCode = int.Parse(rq[0]) << 16 | int.Parse(rq[1]);
                            if (_config.ProcessModuleList.ContainsKey(requestCode))
                                continue; //忽略重复配置加载

                            string assemblyName = node.Get("AssemblyName");
                            string className = node.Get("ClassName");
                            string functionName = node.Get("FunctionName");
                            bool checkNewNotify = node.GetBool("CheckNewNotify");
                            bool reusable = node.GetBool("Reusable", true);
                            bool requireValidate = node.GetBool("RequireValidate");
                            string requirePermission = node.Get("RequirePermission");
                            bool disabled = node.GetBool("Disabled");
                            string description = node.Get("Description");

                            AssemblyInfo assembly = _config.AssemblyList[assemblyName];
                            object processor = assembly.Assembly.CreateInstance(string.Format("{0}.{1}", assembly.NameSpace, className));
                            ProcessModuleInfo module = new ProcessModuleInfo(processor)
                            {
                                RequestCode = requestCode,
                                FunctionName = functionName,
                                CheckNewNotify = checkNewNotify,
                                Reusable = reusable,
                                RequireValidate = requireValidate,
                                RequirePermission = requirePermission,
                                Disabled = disabled,
                                Description = description,
                                ClassName = className,
                                AssemblyName = assemblyName
                            };
                            //_config.ProcessModuleList.Add(module.RequestCode, module);
                            if (_config.ProcessModuleList.ContainsKey(module.RequestCode) && _config.ProcessModuleList[module.RequestCode].ClassName != className)
                                _t(string.Format("duplicate request code({0}) assign for {1} and {2}", module.RequestCode, _config.ProcessModuleList[module.RequestCode].ClassName, className));
                            _config.ProcessModuleList.AddOrSet(module.RequestCode, module);
                        }
                        catch (Exception ex)
                        {
                            _t("Read ProcessModuleList Node Error.", ex);
                        }
                    }
                }
                #endregion

                #region 验证模块ValidateModule
                XmlNode validateModuleNode = section.SelectSingleNode("ValidateModule");
                if (validateModuleNode != null)
                {
                    try
                    {
                        string moduleAssemblyName = validateModuleNode.Attributes["AssemblyName"].Value;
                        string moduleClassName = validateModuleNode.Attributes["ClassName"].Value;

                        AssemblyInfo moduleAssembly = _config.AssemblyList[moduleAssemblyName];
                        IServiceProcessor validateModule = moduleAssembly.Assembly.CreateInstance(string.Format("{0}.{1}", moduleAssembly.NameSpace, moduleClassName)) as IServiceProcessor;
                        if (validateModule != null)
                        {
                            _config.AuthenModule = validateModule;
                        }
                    }
                    catch (Exception ex)
                    {
                        _t("Read ValidateModule Node Error.", ex);
                    }
                }
                #endregion

                //#region 检查最新通知模块CheckNotifyModule
                //XmlNode checkNotifyModuleNode = section.SelectSingleNode("CheckNotifyModule");
                //if (checkNotifyModuleNode != null)
                //{
                //    try
                //    {
                //        string notifyModuleAssembly = validateModuleNode.Attributes["AssemblyName"].Value;
                //        string notifyModuleClass = validateModuleNode.Attributes["ClassName"].Value;
                //        AssemblyInfo checkNotifyAssembly = _config.AssemblyList[notifyModuleAssembly];
                //        //Type notifyModuleType = Type.GetType(string.Format("{0}.{1}", checkNotifyAssembly.NameSpace, notifyModuleClassName));
                //        IServiceProcessor checkNewNotifyProcessor = checkNotifyAssembly.Assembly.CreateInstance(string.Format("{0}.{1}", checkNotifyAssembly.NameSpace, notifyModuleClass)) as IServiceProcessor;
                //        if (checkNewNotifyProcessor != null)
                //        {
                //            _config.CheckNewNotifyModule = checkNewNotifyProcessor;
                //        }
                //    }
                //    catch (Exception ex)
                //    {
                //        _t("Read checkNotifyModuleNode Node Error.", ex);
                //    }
                //}
                //#endregion

                #region 扩展插件列表
                XmlNode extendModuleListNode = section.SelectSingleNode("ExtendModuleList");
                if (extendModuleListNode != null)
                {
                    foreach (XmlNode node in extendModuleListNode.ChildNodes)
                    {
                        try
                        {
                            if (node.NodeType == XmlNodeType.Comment)
                                continue;
                            string assemblyName = node.Attributes["AssemblyName"].Value;
                            string className = node.Attributes["ClassName"].Value;
                            string disabled = node.Attributes["Disabled"].Value;
                            AssemblyInfo extendModuleAssembly = _config.AssemblyList[assemblyName];
                            //Type extendModuleType = Type.GetType(string.Format("{0}.{1}", extendModuleAssembly.NameSpace, className));
                            IServiceExtentProcessor serviceProcessor = extendModuleAssembly.Assembly.CreateInstance(string.Format("{0}.{1}", extendModuleAssembly.NameSpace, className)) as IServiceExtentProcessor;
                            if (serviceProcessor != null)
                            {
                                _config.ExtentProcessor.Add(serviceProcessor);
                            }
                        }
                        catch (Exception ex)
                        {
                            _t("Read ExtendModuleList Node Error.", ex);
                        }

                    }
                }
                #endregion

                #region 支持语言的种类
                XmlNode supportedLanguageLcidNode = section.SelectSingleNode("SupportedLanguageLcid");
                _config.SupportedLanguage = new List<Int16>() { 2052, 1033 };
                if (supportedLanguageLcidNode != null)
                {
                    try
                    {
                        string languageString = supportedLanguageLcidNode.FirstChild.Value;
                        string[] languageArr = languageString.Split(',');
                        _config.SupportedLanguage = new List<Int16>();
                        if (languageArr.Length > 0)
                        {
                            for (int i = 0; i < languageArr.Length; i++)
                            {
                                _config.SupportedLanguage.Add(Int16.Parse(languageArr[i].ToString()));
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _t("Read supportedLanguageLcid Node Error.", ex);
                    }
                }
                #endregion


                #region 服务器地址
                XmlNode serverAddressListNode = section.SelectSingleNode("AppServerAddress");
                if (serverAddressListNode != null)
                {
                    foreach (XmlNode node in serverAddressListNode.ChildNodes)
                    {
                        try
                        {
                            if (node.NodeType == XmlNodeType.Comment)
                                continue;
                            int key = int.Parse(node.Attributes["AppCode"].Value);
                            string url = node.Attributes["Url"].Value;

                            _config.AppServerAddress.AddOrSet(key, url);

                        }
                        catch (Exception ex)
                        {
                            _t("Read AppServerAddress Node Error.", ex);
                        }

                    }
                }
                #endregion

                #region 软件升级FTP地址
                XmlNode upgradeFtpNode = section.SelectSingleNode("UpgradeInfoFtp");
                if (upgradeFtpNode != null)
                {
                    try
                    {
                        XmlNode node = upgradeFtpNode.ChildNodes[0];
                        if (node.NodeType != XmlNodeType.Comment)
                        {
                            _config.UpgradeFtpInfo.Address = node.Attributes["Address"].Value;
                            _config.UpgradeFtpInfo.User = node.Attributes["User"].Value;
                            _config.UpgradeFtpInfo.Password = node.Attributes["Password"].Value;
                        }
                    }
                    catch (Exception ex)
                    {
                        _t("Read UpgradeInfoFtp Node Error.", ex);
                    }
                }
                #endregion

            }
            catch (Exception ex)
            {
                _t("配置加载出错.", ex);
            }
            _config.LoadTraceMessage = Tracer.ToString();
            //ILogger loger = LoggingManager.GetLogger("RpcService");
            //if (loger != null)
            //    loger.Error(_config.LoadTraceMessage);
            _config.LoadTime = DateTime.Now;
        }


        public object Create(object parent, object configContext, XmlNode section)
        {
            _t(DateTime.Now.ToString(), "Start to load rpcservice Config.");
            loadConfig(section);
            return _config;
        }
    }
}
